/**
@author		Jong Min, Lee
@date		  02/07/2014
@breif		monitor group property

copyright(c) Tae Young Soft. All right reserved. 2014
*/
#include "stdafx.h"
#include "Taurus_Viewer/MonitorGroupProperty.h"
#include <algorithm>
#include "Taurus_Util/Errors.h"
#include "Taurus_Viewer/MonitorWnd.h"
#include "Taurus_Viewer/StudyWorkSpace.h"

CMonitorGroup::~CMonitorGroup()
{
  m_theItems.clear();
  for(unsigned i = 0; i < m_theSWSGroup.size(); ++i)
  {
    _DELETE(m_theSWSGroup[i]);
  }
  m_theSWSGroup.clear();
}

BOOL CMonitorGroup::getIndex(const CMonitorWnd* monitorWnd, unsigned int& index) const
{
  auto pos = find_if(m_theItems.cbegin(), m_theItems.cend(),
    [&monitorWnd](const CMonitorWnd* m)
  {
    return monitorWnd == m;
  });

  if(pos != m_theItems.cend())
  {
    index = std::distance(m_theItems.cbegin(), pos);
    return TRUE;
  }

  return FALSE;
}

BOOL CMonitorGroup::isExist(const CMonitorWnd* monitorWnd) const
{
  auto pos = find_if(m_theItems.cbegin(), m_theItems.cend(),
    [&monitorWnd](const CMonitorWnd* m)
  {
    return monitorWnd == m;
  });

  return pos != m_theItems.cend();
}

unsigned int CMonitorGroup::getNumSWSs(const unsigned int index) const
{
  if(index >= m_theSWSGroup.size()) return 0;

  return m_theSWSGroup[index]->size();
}

DWORD CMonitorGroup::addSWS(const unsigned int index, const CStudyWorkSpace& sws)
{
  if(index >= m_theSWSGroup.size()) return ERROR_INVALID_PARAMETER;

  try
  {
    m_theSWSGroup[index]->push_back(&sws);
  }
  catch(...)
  {
    return ERROR_NOT_ENOUGH_MEMORY;
  }

  return ERROR_SUCCESS;
}

const CStudyWorkSpace* CMonitorGroup::getSWS(const unsigned int monitorIndex, 
                                             const unsigned int swsIndex) const
{
  if(monitorIndex >= m_theSWSGroup.size()) return NULL;

  if(swsIndex >= m_theSWSGroup[monitorIndex]->size()) return NULL; 

  return (*m_theSWSGroup[monitorIndex])[swsIndex];
}

void CMonitorGroup::clearSWSGroup()
{
  unsigned int numGrops = m_theSWSGroup.size();
  for(unsigned int i = 0; i < numGrops; ++i)
  {
    m_theSWSGroup[i]->clear();
  }
}

CMonitorGroupProperty::CMonitorGroupProperty()
  : m_arrItems(nullptr)
  , m_nNumItems(0)
{}

CMonitorGroupProperty::~CMonitorGroupProperty()
{
  removeAllGroups();
}

DWORD CMonitorGroupProperty::groupMonitors(const TCHAR* pszLayout, 
                                           std::vector<CMonitorWnd*>& arrMonitrWnds)
{
  if(pszLayout == NULL) return ERROR_INVALID_PARAMETER;

  //parse layout string
  unsigned int nTotalMonitorCount = 0;
  std::vector<unsigned> arrMonitorCount;
  DWORD dwError = parseLayoutStr(pszLayout, arrMonitorCount, nTotalMonitorCount);
  if(dwError != ERROR_SUCCESS) return dwError;

  //the number of monitors that be involved in layout must be equal to arrMonitorWnd size
  if(nTotalMonitorCount != arrMonitrWnds.size())
    return ERROR_ILLEGAL_MONITOR_GROUP;

  //allocate memory for new monitor groups
  unsigned int nNumGroups = arrMonitorCount.size();
  CMonitorGroup** arrNewGroups = NULL;
  _TRY_ALLOC(arrNewGroups, CMonitorGroup*[nNumGroups]);
  if(arrNewGroups == nullptr) return ERROR_NOT_ENOUGH_MEMORY;
  memset(arrNewGroups, 0, sizeof(CMonitorGroup*) * nNumGroups);

  for(unsigned int nGroupIndex = 0; nGroupIndex < nNumGroups; ++nGroupIndex)
  {
    CMonitorGroup* pGroup = NULL;
    _TRY_ALLOC(pGroup, CMonitorGroup);
    if(pGroup == nullptr)
    {
      dwError = ERROR_NOT_ENOUGH_MEMORY;
      break;
    }
    arrNewGroups[nGroupIndex] = pGroup;
  }


  if(dwError != ERROR_SUCCESS)
  {
    for(unsigned int i = 0; i < nNumGroups; ++i)
      _DELETE(arrNewGroups[i]);
    _DELETE_ARR(arrNewGroups);
    return dwError;
  }

  //add monitor windows to each monitor groups
  unsigned nCurrentMonitorIdx = 0;
  for(unsigned int nGroupIndex = 0; nGroupIndex < nNumGroups; ++nGroupIndex)
  {
    unsigned nNumMonitorItems = arrMonitorCount[nGroupIndex];
    CMonitorGroup* pGroup = arrNewGroups[nGroupIndex];

    _TRY_BEGIN
    pGroup->m_theItems.reserve(nNumMonitorItems);
    pGroup->m_theSWSGroup.reserve(nNumMonitorItems);
    _CATCH_ALL
    dwError = ERROR_NOT_ENOUGH_MEMORY;
    break;
    _CATCH_END

    for(unsigned iMonitorIdex = 0; iMonitorIdex < nNumMonitorItems; ++iMonitorIdex)
    {
      CMonitorWnd* pMonitorWnd = arrMonitrWnds[nCurrentMonitorIdx++];
      pGroup->m_theItems.push_back(pMonitorWnd);

      std::vector<const CStudyWorkSpace*>* swsGroup = NULL;
      _TRY_ALLOC(swsGroup, std::vector<const CStudyWorkSpace*>)
      if(swsGroup == NULL) 
      {
        dwError = ERROR_NOT_ENOUGH_MEMORY;
        break;
      }
      pGroup->m_theSWSGroup.push_back(swsGroup);
    }
  }
  if(dwError != ERROR_SUCCESS)
  {
    for(unsigned int i = 0; i < nNumGroups; ++i)
      _DELETE(arrNewGroups[i]);
    _DELETE_ARR(arrNewGroups);
    return dwError;
  }

  removeAllGroups();
  m_arrItems = arrNewGroups;
  m_nNumItems = nNumGroups;
  return ERROR_SUCCESS;
}

const CMonitorGroup* CMonitorGroupProperty::getItem(unsigned index) const
{
  if(index >= m_nNumItems)  return nullptr;

  return m_arrItems[index];
}

const CMonitorGroup* CMonitorGroupProperty::findItem(const CMonitorWnd* monitorWnd, 
                                                     unsigned int* index) const
{
  const CMonitorGroup* outGroup = NULL;
  unsigned int outIndex = 0;
  for(unsigned int i = 0; i < m_nNumItems; ++i, ++outIndex)
  {
    if(m_arrItems[i]->isExist(monitorWnd))
    {
      if(index != NULL) *index = outIndex;
      return m_arrItems[i];
    }
  }
  return NULL;
}

DWORD CMonitorGroupProperty::addSWS(const unsigned int groupIndex, 
                                    const unsigned int monitorIndex, 
                                    const CStudyWorkSpace& sws)
{
  if(groupIndex >= m_nNumItems) return ERROR_INVALID_PARAMETER;

  return m_arrItems[groupIndex]->addSWS(monitorIndex, sws);
}

void CMonitorGroupProperty::clearSWSGroups()
{
  for(unsigned int i = 0; i < m_nNumItems; ++i)
  {
    m_arrItems[i]->clearSWSGroup();
  }
}

CString CMonitorGroupProperty::convertToStr() const
{
  CString strGroup;
  CString strTemp;
  for(unsigned int i = 0; i < m_nNumItems; ++i)
  {
    CMonitorGroup* pGroup = m_arrItems[i];
    strTemp.Format(_T("%d"), pGroup->getNumItems());
    strGroup += strTemp;

    if(i != m_nNumItems - 1) strGroup += _T("-");
  }

  return strGroup;
}

DWORD CMonitorGroupProperty::parseLayoutStr(const TCHAR* pszLayout, 
                                            std::vector<unsigned>& arrMonitorCount, 
                                            unsigned int& nTotalCount)
{
  CString strLayout;
  try 
  { 
    strLayout = pszLayout; 
  }
  catch(CMemoryException* e)
  {
    e->Delete();
    return ERROR_NOT_ENOUGH_MEMORY;
  }

  nTotalCount = 0;
  bool isLegl = true;
  for(int i = 0; i < strLayout.GetLength(); ++i)
  {
    if(!((strLayout[i] > 0x29 && strLayout[i] < 0x40) ||
         (strLayout[i] == _T('-'))))
    {
      isLegl = false;
      break;
    }
  }

  if(!isLegl)
    return ERROR_ILLEGAL_MONITOR_GROUP;
  arrMonitorCount.clear();
  unsigned nNumMonitors = 0;
  int nIndex = strLayout.Find(_T('-'));
  while(TRUE)
  {
    if(nIndex == -1)
    {
      nNumMonitors = static_cast<unsigned>(_ttoi(strLayout.Left(strLayout.GetLength())));
      _TRY_BEGIN
       arrMonitorCount.push_back(nNumMonitors);
      _CATCH_ALL
       return ERROR_NOT_ENOUGH_MEMORY;
      _CATCH_END

      nTotalCount += nNumMonitors;
      break;
    }

    nNumMonitors = static_cast<unsigned>(_ttoi(strLayout.Left(strLayout.GetLength())));
    _TRY_BEGIN
     arrMonitorCount.push_back(nNumMonitors);
    _CATCH_ALL
     return ERROR_NOT_ENOUGH_MEMORY;
    _CATCH_END

     nTotalCount += nNumMonitors;

     strLayout = strLayout.Right(strLayout.GetLength() - nIndex - 1);
     nIndex = strLayout.Find(_T('-'));
   }

   return ERROR_SUCCESS;
}

void CMonitorGroupProperty::removeAllGroups()
{
  for(unsigned int i = 0; i < m_nNumItems; ++i)
    _DELETE(m_arrItems[i]);
  _DELETE_ARR(m_arrItems);
  m_nNumItems = 0;
}



